//
//  LYCentral.swift
//  RxSwift_Practice
//
//  Created by 李永彬 on 2020/4/28.
//  Copyright © 2020 李永彬. All rights reserved.
//

import Foundation
import CoreBluetooth

let LYBluetoothConnectedNotification: String = "LYBluetoothConnectedNotification"
let LYBluetoothConnectedFromRestoreStateNotification: String = "LYBluetoothConnectedFromRestoreStateNotification"

public class LYCentral:LYPeer, LYCBCentralManagerStateDelegate {
    enum LYBluetoothState: Int {
        case LYBluetoothStateDisable
        case LYBluetoothStateAvailable
        case LYBluetoothStateConnecting
        case LYBluetoothStateDisconnected
        case LYBluetoothStateConnected
    }

    static let shared = LYCentral()
    public typealias ScanProgressHandler = ((_ newDiscoveries: [LYDiscovery]) -> Void)
    public typealias ScanCompletionHandler = ((_ result: [LYDiscovery]?, _ error: LYError?) -> Void)
    public typealias ConnectCompletionHandler = ((_ remotePeripheral: LYRemotePeripheral, _ error: LYError?) -> Void)
    private var centralManagerDelegate: LYCBCentralManagerDelegateProxy!
    private let scanner = LYScanner()
//    private
    let connectionPool = LYConnectionPool()
    private let restorePool = LYRestorePool()
    private var _centralManager: CBCentralManager!
    private var centralManager: CBCentralManager? {
        return _centralManager
    }
    var taskManager: LYBluetoothTaskManager?
    var state: LYBluetoothState?

//    public var remotePeripheral: LYRemotePeripheral!
    
    private var _configuration: LYConfiguration?

    override init() {
        super.init()
        self.centralManagerDelegate = LYCBCentralManagerDelegateProxy(stateDelegate: self, discoveryDelegate: scanner, connectionDelegate: connectionPool, restoreDelegate: restorePool)
        _configuration = LYConfiguration()
        try!self.startWithConfiguration(_configuration!)
    }
    
    public func startWithConfiguration(_ configuration: LYConfiguration) throws {
        let options:[String: Any] = [
            CBCentralManagerOptionShowPowerAlertKey : NSNumber(true),
            CBCentralManagerOptionRestoreIdentifierKey : "centralManagerIdentifier"
        ]
        let infoDic: [String : Any] = Bundle.main.infoDictionary!
        let modes = infoDic["UIBackgroundModes"]
         
        if modes == nil {
            _centralManager = CBCentralManager(delegate: centralManagerDelegate, queue: .main, options: nil)
        } else {
            _centralManager = CBCentralManager(delegate: centralManagerDelegate, queue: .main, options: options)
        }
        scanner.configuration = configuration
        scanner.centralManager = centralManager
        connectionPool.centralManager = centralManager
        restorePool.connectionPool = connectionPool
        restorePool.configuration = configuration
        self.taskManager = LYBluetoothTaskManager()
    }
    
    public func scanWithDuration(_ duration: TimeInterval = 3, updateDuplicates: Bool = false, progressHandler: ScanProgressHandler?, completionHandler: ScanCompletionHandler?) {
        do {
//            try stateMachine.handleEvent(.scan)
//            try scanner.scanWithDuration(duration, updateDuplicates: updateDuplicates, progressHandler: { (result) in
//                
//            }, completionHandler: { result, error in
//                
//            })
            try scanner.scanWithDuration(duration, updateDuplicates: updateDuplicates, progressHandler: progressHandler) { result, error in
                var returnError: LYError?
                if error == nil {
//                    _ = try? self.stateMachine.handleEvent(.setAvailable)
                } else {
                    returnError = .internalError(underlyingError: error)
                }
                completionHandler?(result, returnError)
            }
        } catch let error {
            completionHandler?(nil, .internalError(underlyingError: error))
            return
        }
    }
    
    public func connect(_ timeout: TimeInterval = 3, remotePeripheral: LYRemotePeripheral, completionHandler: @escaping ConnectCompletionHandler) {
        do {
//            try stateMachine.handleEvent(.connect)
            try connectionPool.connectWithTimeout(timeout, remotePeripheral: remotePeripheral) { remotePeripheral, error in
                var returnError: LYError?
                if error == nil {
//                    _ = try? self.stateMachine.handleEvent(.setAvailable)
                } else {
                    returnError = .internalError(underlyingError: error)
                }
                completionHandler(remotePeripheral, returnError)
            }
        } catch let error {
            completionHandler(remotePeripheral, .internalError(underlyingError: error))
            return
        }
    }
    
    public func stop() throws {
        try? interruptScan()
        connectionPool.reset()
        _configuration = nil
        _centralManager = nil
    }
    
    public func interruptScan() throws {
        scanner.interruptScan()
    }
    
    func sendRequest(dataModel:LYBluetoothData, callback: @escaping LYBCRequestCallback) -> LYBluetoothTask? {
        var task: LYBluetoothTask?
        let remotePeripheral:LYRemotePeripheral? = connectionPool.connectedRemotePeripherals.last ?? nil
        if dataModel.type == .LYBlueToothdataTypeNormal {
            task = LYBluetoothDataTask.taskWithDataModelAndDevice(dataModel: dataModel, sendDevice: remotePeripheral, callback: callback)
        }
        else if dataModel.type == .LYBlueToothdataTypeMedia
        {
            task = LYBluetoothResponseTask.taskWithDataModelAndDevice(dataModel: dataModel, sendDevice: remotePeripheral, callback: callback)
        }
        else
        {
            task = LYBluetoothAddressBookTask.taskWithDataModelAndDevice(dataModel: dataModel, sendDevice: remotePeripheral, callback: callback)
        }
        guard task != nil else {
            callback(nil, .LYBCCodeParamsError)
            return task
        }
        self.taskManager?.addTask(task: task!)
        self.taskManager?.beginTask()
        return task
    }

    // MARK: LYCBCentralManagerStateDelegate
    internal func centralManagerDidUpdateState(_ central: CBCentralManager) {
        switch central.state {
        case .unknown:
            print("未知的")
            self.stateUnknown()
        case .resetting:
            print("重置中")
            self.stateResetting()
        case .unsupported:
            print("不支持")
            self.stateUnsuported()
        case .unauthorized:
            print("未验证")
            self.stateUnauthorized()
        case .poweredOff:
            print("未启动")
            self.statePoweredOff()
        case .poweredOn:
            print("可用")
            self.statePoweredOn()
        default:
            print("未知的")
        }
    }
    
    func stateUnknown() {
        self.state = .LYBluetoothStateDisable
    }
    
    func stateResetting() {
        self.state = .LYBluetoothStateDisable
    }
    
    func stateUnsuported() {
        self.state = .LYBluetoothStateDisable
    }
    
    func stateUnauthorized() {
        self.state = .LYBluetoothStateDisable
    }
    
    func statePoweredOff() {
        self.state = .LYBluetoothStateDisable
        self.taskManager?.handBlePowerOff()
        self.connectionPool.reset()
    }
    
    func statePoweredOn() {
        self.state = .LYBluetoothStateAvailable
    }
}
